package core

import (
	"fmt"
	"net/http"
	"os"
	"time"

	"github.com/gin-gonic/gin"
)

type JsonResponse struct {
	Result  any    `json:"result"`
	Message string `json:"message"`
	Code    int64  `json:"code"`
	Success bool   `json:"success"`
}

type HttpRouter struct {
}

func (o *HttpRouter) BuildRouterMap() map[string]map[string]any {
	routerMap := map[string]map[string]any{
		"/capture": {
			"method": http.MethodGet,
			"handle": o.getCapture,
		}, // 视频流截图
		"/ptz/command": {
			"method": http.MethodPost,
			"handle": o.ptzCommand,
		},
	}
	return routerMap
}

var (
	captureChans = map[string]chan string{} // 视频流截图通道
	ptzChan      = map[string]chan string{} // ptz命令执行完毕回传通道
)

// 截取流中图片,get请求
func (o *HttpRouter) getCapture(c *gin.Context) {
	// 请求参数为通道号ch，例如ch=55
	chCode := c.Query("ch")
	var jsonResponse JsonResponse
	jsonResponse.Code = http.StatusOK
	if chCode == "" {
		jsonResponse.Message = "编码为空"
		jsonResponse.Result = map[string]string{}
		c.JSON(http.StatusOK, jsonResponse)
		return
	}
	// 判断通道是否在系统中
	if _, ok := dispatcher.ChannelMap["ch"+chCode]; !ok {
		jsonResponse.Message = "编码数据不存在"
		jsonResponse.Result = map[string]string{}
		c.JSON(http.StatusOK, jsonResponse)
		return
	}
	// 初始化一个新的通道用来接收客户端的发送的截图文件流地址，长度为一个缓冲区
	captureChans[chCode] = make(chan string, 1)

	// 发送编码数据给pusher客户端，等其对应的返回
	if ch, ok := dispatcher.ChannelMap["ch"+chCode]; ok {
		dispatcher.SendSignal(ch, &Message{Sign: SIG_CAPTURE, Chan: ch.Code}, 1)
	}
	c.Header("Content-Type", "application/octet-stream")
	c.Header("Content-Disposition", fmt.Sprintf("attachment; filename=capture-%s.jpg", chCode))
	// 从通道中接收完成的图片地址
	G.Log.Infof("[HttpServer] Wait receive channel code [%s] capture", chCode)
	select {
	case path := <-captureChans[chCode]:
		G.Log.Infof("[HttpServer] has receive channel code [%s] capture, path is [%s]", chCode, path)
		c.File(path)
		os.Remove(path)
		return
	case <-time.After(time.Second * 25):
		jsonResponse.Message = "请求超时"
		jsonResponse.Result = map[string]string{}
		c.JSON(http.StatusOK, jsonResponse)
		return
	}
}

// 执行ptz指令
func (o *HttpRouter) ptzCommand(c *gin.Context) {
	var jsonResponse JsonResponse
	var dataStruct struct {
		Ch      string `json:"ch"`
		Command string `json:"command"`
	}
	err := c.ShouldBindJSON(&dataStruct)
	jsonResponse.Code = http.StatusOK
	if err != nil {
		jsonResponse.Message = "解析参数失败"
		jsonResponse.Result = map[string]string{}
		c.JSON(http.StatusOK, jsonResponse)
		return
	}
	chCode := dataStruct.Ch
	if chCode == "" {
		jsonResponse.Message = "通道编码为空"
		jsonResponse.Result = "操作失败"
		c.JSON(http.StatusOK, jsonResponse)
		return
	}
	// 判断通道是否在系统中
	if _, ok := dispatcher.ChannelMap["ch"+chCode]; !ok {
		jsonResponse.Message = "通道编码数据不存在"
		jsonResponse.Result = "操作失败"
		c.JSON(http.StatusOK, jsonResponse)
		return
	}
	// 判断通道是否可控
	channel := dispatcher.ChannelMap["ch"+chCode]
	if channel.IsControllable == 0 {
		jsonResponse.Message = "该通道不可控"
		jsonResponse.Result = "操作失败"
		c.JSON(http.StatusOK, jsonResponse)
		return
	}
	commandMap := map[string]bool{
		"left":       true, // 向左移动
		"right":      true, // 向右移动
		"up":         true, // 向上移动
		"down":       true, // 向下移动
		"up_left":    true, // 向上左移动
		"up_right":   true, // 向上右移动
		"down_left":  true, // 向下左移动
		"down_right": true, // 向下右移动
		"zoom_in":    true, // 放大镜头
		"zoom_out":   true, // 缩小镜头
	}
	// 判断指令是否在支持的map中
	command := dataStruct.Command
	if _, ok := commandMap[command]; !ok {
		jsonResponse.Message = fmt.Sprintf("当前指令[%s]不支持", command)
		jsonResponse.Result = "操作失败"
		c.JSON(http.StatusOK, jsonResponse)
		return
	}
	ptzChan[chCode] = make(chan string, 1)
	// 发送编码数据给pusher客户端，等其对应的返回
	if ch, ok := dispatcher.ChannelMap["ch"+chCode]; ok {
		dispatcher.SendSignal(ch, &Message{Sign: SIG_PTZ_START, Chan: ch.Code, Content: command}, 1)
	}

	select {
	case content := <-ptzChan[chCode]:
		switch content {
		case SIG_PTZ_FAIL:
			jsonResponse.Message = fmt.Sprintf("执行指令[%s]失败", command)
			jsonResponse.Result = "操作失败"
			c.JSON(http.StatusOK, jsonResponse)
			return
		case SIG_PTZ_NOT_FOUND:
			jsonResponse.Message = fmt.Sprint("当前通道不支持云台操作或通道不存在")
			jsonResponse.Result = "操作失败"
			c.JSON(http.StatusOK, jsonResponse)
			return
		case SIG_PTZ_SUCCESS:
			jsonResponse.Message = fmt.Sprintf("执行指令[%s]成功", command)
			jsonResponse.Result = "操作成功"
			jsonResponse.Success = true
			c.JSON(http.StatusOK, jsonResponse)
			return
		default:
			jsonResponse.Message = fmt.Sprintf("执行指令[%s]失败", command)
			jsonResponse.Result = "操作失败"
			c.JSON(http.StatusOK, jsonResponse)
			return
		}
	case <-time.After(time.Second * 10):
		jsonResponse.Message = "执行指令超时"
		jsonResponse.Result = map[string]string{}
		c.JSON(http.StatusOK, jsonResponse)
		return
	}
}
